package org.javaboy.jwt_redis_demo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.javaboy.jwt_redis_demo.model.RespBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.SecurityContextHolderFilter;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.concurrent.TimeUnit;

@Configuration
public class SecurityConfig {

//    @Autowired
//    JwtFilter jwtFilter;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Bean
    UserDetailsService us() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("{noop}abc").roles("USER").build());
        return manager;
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a -> a.anyRequest().authenticated())
                .csrf(c -> c.disable())
                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .formLogin(f -> f
                        .successHandler((req, resp, auth) -> {
                            //登录成功，生成 JWT 字符串
                            try {
                                String token = JwtUtils.createJWT();
                                //将 JWT 字符串保存到 redis 中
                                redisTemplate.opsForValue().set(auth.getName() + ":" + token, auth.getName());
                                // 设置过期时间
                                redisTemplate.expire(auth.getName() + ":" + token, JwtUtils.REDIS_TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
                                resp.setContentType("application/json;charset=utf-8");
                                RespBean respBean = new RespBean(200, token, null);
                                resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                            } catch (NoSuchAlgorithmException e) {
                                throw new RuntimeException(e);
                            } catch (InvalidKeySpecException e) {
                                throw new RuntimeException(e);
                            }
                        })
                        .permitAll())
                .logout(l -> l.logoutSuccessHandler((req, resp, auth) -> {
                    // 删除 redis 中的 token
                    String key = auth.getName() + ":" + req.getHeader("Authorization").replace("Bearer ", "");
                    System.out.println("key = " + key);
                    redisTemplate.delete(key);
                    resp.getWriter().write("logout success");
                }).logoutUrl("/logout").permitAll());
        http.addFilterAfter(new JwtFilter(redisTemplate), SecurityContextHolderFilter.class);
        return http.build();
    }
}
